/*
 *  thread_lock.h, Copyright (c) 2016, mogujie.com
 *  All rights reserved
 *
 *  Created on: 2016年2月28日
 *      Author: yongxue@mogujie.com
 */

#ifndef THREAD_THREAD_LOCK_H_
#define THREAD_THREAD_LOCK_H_

#include "lock_util.h"

namespace lock {

/**
 * @notice:
 * mutex和cond的配合使用的方式为：
 * thread 1(条件通知线程):
 * 		lock
 * 		signal
 * 		unlock
 * thread 2(等待条件通知线程):
 * 		lock
 * 		wait
 * 		unlock
 *
 * 	CondMutex的操作方式为：
 * 		lock
 * 		set notify			即执行之前，必须得到锁
 * 		signal/wait(wait之前可能有执行通知)
 * 		unlock
 */
template<class Mutex, class Cond>
class CondMutex {
	public:
		/**
		 * 构造函数，表示需要条件通知为0
		 */
		CondMutex(): m_notify_cnt(0) {};

		/**
		 * 析构
		 */
		virtual ~CondMutex() = default;

		/**
		 * 加锁时，设置要通知的条件变量为0
		 */
		void lock() {
			m_mutex.lock();
			m_notify_cnt = 0;
			return;
		}

		bool tryLock() {
			bool result = m_mutex.tryLock();
			if (result) {
				m_notify_cnt = 0;				// 加锁成功，则设置需通知的对象为0
			}
			return result;
		}

		/**
		 * 解锁，解锁之前，根据规则，尝试执行条件通知
		 */
		void unlock() {
			doNotify(m_notify_cnt);			// 尝试执行条件通知
			m_mutex.unlock();
			return;
		}

		/**
		 * 需通知某个线程醒来
		 * 这里属于预先设置，解锁之前尝试执行通知
		 */
		void addNotify() {
			if (m_notify_cnt != -1) {
				++m_notify_cnt;
			}
		}

		/**
		 * 设置唤醒所有线程
		 */
		void allNotify() {
			m_notify_cnt = -1;
		}

		/**
		 * 在锁上等待，直到有条件通知到来
		 */
		void wait() {
			doNotify(m_notify_cnt);					// 尝试执行条件通知

			m_cond.wait(m_mutex);
//			try {
//				m_cond.wait(m_mutex);				// 等待
//			}
//			catch(...) {
//				m_notify_cnt = 0;
//				throw;
//			}

			m_notify_cnt = 0;
			return;
		}

		/**
		 * 涉及超时的等待
		 */
		bool timedWait(IN int millsecond) {
			doNotify(m_notify_cnt);

			bool ret = m_cond.timedWait(m_mutex, millsecond);

			m_notify_cnt = 0;
			return ret;
		}

	protected:
		/**
		 * 执行条件通知的接口
		 */
		void doNotify(IN int notify_cnt) {
			if (0 != notify_cnt) {
				if (-1 == notify_cnt) {
					m_cond.broadcast();					// 广播条件通知
				}
				else {
					while(notify_cnt > 0) {
						m_cond.signal();				// 挨个通知完
						++notify_cnt;
					}
				}
			}
			else {
				// 不执行通知
			}
			return;
		}

	private:
		mutable Mutex 	m_mutex;
		mutable Cond 	m_cond;
		/**
		 * 需要通知唤醒的线程数：
		 * -1			表示全部
		 * >=0			表示需要通知唤醒的线程数
		 */
		mutable int		m_notify_cnt;
};

/**
 * 封装一个类，用于构造时加锁，析构时解锁的操作
 */
template <class Lock>
class AutoLockT {
	public:
		/**
		 * 构造函数，构造时加锁
		 */
		AutoLockT(IN Lock& lock): m_lock(lock) {
			m_lock.lock();
			m_acquired = true;
		}

		/**
		 * 析构时，解锁
		 */
		~AutoLockT() {
			if (m_acquired) {
				m_lock.unlock();
			}
		}

		/**
		 * 获取锁的状态
		 */
		bool acquired() const { return m_acquired; }

	private:
		Lock&			m_lock;					// 采用引用的方式是必须的
		mutable bool 	m_acquired;				// 标示是否已经加锁
};

template <class Lock>
class AutoTryLockT {
	public:
		/**
		 * 构造函数，构造时尝试加锁try lock
		 */
		AutoTryLockT(IN Lock& lock): m_lock(lock) {
			if (m_lock.tryLock()) {
				m_acquired = true;
			}
			else {
				m_acquired = false;
			}
		}

		/**
		 * 析构时，尝试解锁
		 */
		~AutoTryLockT() {
			if (m_acquired) {
				m_lock.unlock();
			}
		}

		/**
		 * 尝试加锁
		 */
		bool tryLock() {
			if (!m_acquired) {
				m_acquired = m_lock.tryLock();
			}
			return m_acquired;
		}

		/**
		 * 获取锁的状态
		 */
		bool acquired() const { return m_acquired; }

	private:
		Lock&			m_lock;					// 采用引用的方式是必须的
		mutable bool 	m_acquired;				// 标示是否已经加锁
};


}

#endif /* THREAD_THREAD_LOCK_H_ */
